﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;
using AvalonDock;
using Color = System.Windows.Media.Color;
using ColorConverter = System.Windows.Media.ColorConverter;
using DataFormats = System.Windows.DataFormats;
using DragDropEffects = System.Windows.DragDropEffects;
using DragEventArgs = System.Windows.DragEventArgs;
using FlowDirection = System.Windows.FlowDirection;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MenuItem = System.Windows.Controls.MenuItem;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;

namespace Poet
{
    /// <summary>
    /// Main Window
    /// </summary>
    public partial class MainWindow
    {
        public static RoutedCommand Find = new RoutedCommand();
        public static RoutedCommand Exit = new RoutedCommand();
        public static RoutedCommand SaveAll = new RoutedCommand();

        private readonly FindAndReplaceDialog _searchAndReplaceDialog = new FindAndReplaceDialog
                                                                            {Title = "Find and Repace"};

        public static ObservableCollection<DocumentContent> Documents { get; private set; }
        private readonly Regex _newDocNameRegex = new Regex(@"New \(\d+\)");
        private ChildWindow _lastActiveChild;
        private int _countOfNewDocuments;

        public MainWindow()
        {
            Documents = new ObservableCollection<DocumentContent>();
            InitializeComponent();
            Grid.DataContext = this;
            
            AppInstanceManager.OnReciveArguments += OpenFiles;

            MenuItemClick("StandartView");
        }

        private void DockingManagerActiveContentChanged(object sender, EventArgs e)
        {
            var child = dockingManager.ActiveContent as ChildWindow;

            if (_lastActiveChild != null)
            {
                _lastActiveChild._textEditor.TextArea.DisableCaretHide = false;
                _lastActiveChild._textEditor.TextArea.Caret.Hide();
            }

            _lastActiveChild = child;

            if (child == null) return;

            if (child.IsFloating)
            {
                FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), this);
            }

            var textEditor = child._textEditor;
            var textArea = child._textEditor.TextArea;
            textArea.DisableCaretHide = true;
            textArea.Caret.Show();

            _closeMenuItem.CommandTarget =
                _saveMenuItem.CommandTarget =
                _saveAsMenuItem.CommandTarget = child;

            button1.CommandTarget =
                button2.CommandTarget =
                button3.CommandTarget =
                button4.CommandTarget =
                button5.CommandTarget =
                button6.CommandTarget =
                button7.CommandTarget = textArea;

            item1.CommandTarget =
                item2.CommandTarget =
                item3.CommandTarget =
                item4.CommandTarget =
                item5.CommandTarget =
                item6.CommandTarget =
                item7.CommandTarget = textArea;

            HighlightToolBar.DataContext = textEditor;
            FormatMenuItem.DataContext = textEditor;
            FormatToolBar.DataContext = textEditor;
            foldingCheckBox.DataContext = child;

            textArea.Caret.PositionChanged -= OnCaretPositionChanged;
            textArea.Caret.PositionChanged += OnCaretPositionChanged;
            OnCaretPositionChanged(null, null);

            FilePathStatusBarItem.Content = string.IsNullOrEmpty(child.FileName)
                                                ? child.Title
                                                : child.FileName;
            FilePathStatusBarItem.ToolTip = FilePathStatusBarItem.Content;

            flowCheckBox.IsChecked =
                textEditor.FlowDirection != FlowDirection.LeftToRight;
            CheckBox8Click(null, null);
        }

        private void OnCaretPositionChanged(object o, EventArgs e)
        {
            var child = dockingManager.ActiveContent as ChildWindow;
            if (child == null) return;

            LineNumberStatusBarItem.Content = string.Format("Line {0}\t\tCol {1}\t\t",
                                                            child._textEditor.TextArea.Caret.Line,
                                                            child._textEditor.TextArea.Caret.Column);
        }

        private void ComboBox1SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var child = dockingManager.ActiveContent as ChildWindow;
            if (child == null) return;
            child.HighlightingComboBoxSelectionChanged(null, null);
        }

        private void WindowKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape && dockingManager.ActiveContent != null)
            {
                var pane = dockingManager.ActiveContent.ContainerPane;
                dockingManager.ActiveContent.Close();
                var descendants = pane.LogicalDescendants<ManagedContent>();
                var activeDocument = descendants.FirstOrDefault(d => d.IsActiveDocument);
                if (activeDocument != null) activeDocument.Activate();
            }

            if (Documents.Count == 0)
            {
                if (e.Key == Key.Space) New(null, null);
                if (e.Key == Key.Enter) Open(null, null);
            }

            if (_lastActiveChild != null &&
                _lastActiveChild.IsFloating &&
                e.Handled == false)
                _lastActiveChild._textEditor.TextArea.RaiseEvent(e);
        }

        private void MenuItemClick(object sender, RoutedEventArgs e)
        {
            if (!(sender is MenuItem)) return;
            var tag = ((MenuItem) sender).Tag as string;
            MenuItemClick(tag);
        }

        private void MenuItemClick(string tag)
        {
            switch (tag)
            {
                case "ToolStyle":

                    break;

                case "LightView":
                    foreach (var toolBar in ToolBarTray.ToolBars)
                    {
                        toolBar.Visibility = Visibility.Collapsed;
                    }

                    MainStatusBar.Visibility = Visibility.Collapsed;
                    break;

                case "StandartView":
                    foreach (var toolBar in ToolBarTray.ToolBars)
                    {
                        toolBar.Visibility = Visibility.Collapsed;
                    }

                    StandartToolBar.Visibility = Visibility.Visible;
                    MainStatusBar.Visibility = Visibility.Visible;
                    break;

                case "RichView":
                    foreach (var toolBar in ToolBarTray.ToolBars)
                    {
                        toolBar.Visibility = Visibility.Visible;
                    }

                    MainStatusBar.Visibility = Visibility.Visible;
                    break;

                case "ChangeAeroThemeColor":
                    var d = new ColorDialog();
                    if (d.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        ThemeFactory.ChangeColors(Color.FromRgb(d.Color.R, d.Color.G, d.Color.B));
                    }

                    break;

                case "About":
                    new AboutDialog { Owner = this }.ShowDialog();
                    break;

                case "Help":
                    MessageBox.Show("Sorry, help temporary not available\n on current alpha version of this program.");
                    break;

                case "Compact":
                    WindowStyle = WindowStyle.ToolWindow;
                    WindowState = WindowState.Normal;
                    Width = Height = 400;
                    Topmost = true;
                    break;

                case "ShowNavigatorWindow":
                    dockingManager.ShowNavigatorWindow();
                    break;
            }
        }

        private void CheckBox8Click(object sender, RoutedEventArgs e)
        {
            var child = dockingManager.ActiveContent as ChildWindow;
            if (child == null) return;
            if (flowCheckBox.IsChecked == false)
            {
                checkBox8text.Text = "→";
                child._textEditor.FlowDirection = FlowDirection.LeftToRight;
            }
            else
            {
                checkBox8text.Text = "←";
                child._textEditor.FlowDirection = FlowDirection.RightToLeft;
            }
        }

        private void SaveAllExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            foreach (var childWindow in Documents.OfType<ChildWindow>())
            {
                childWindow.Save_Executed(sender, e);
            }
        }

        private void SaveAllCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = Documents.Count > 0;
            if (HelpStatusBarItem != null)
                HelpStatusBarItem.Visibility = e.CanExecute
                                                   ? Visibility.Collapsed
                                                   : Visibility.Visible;
        }

        private void ExitExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            Environment.Exit(0);
        }

        private void New(object sender, ExecutedRoutedEventArgs e)
        {
            var newDocuments = Documents.Where(d => _newDocNameRegex.IsMatch(d.Title));

            var nameForNewDocument = "New " + ++_countOfNewDocuments;
            do
            {
                var documentName = nameForNewDocument;
                var documentWithSameName = newDocuments.
                    FirstOrDefault(d => d.Title == documentName);
                if (documentWithSameName == null) break;
                nameForNewDocument = "New " + ++_countOfNewDocuments;
            } while (true);

            var child = ChildWindow.CreateNew(nameForNewDocument);
            // if (dockingManager.ActiveDocument != null &&
            //     !((DocumentContent) dockingManager.ActiveDocument).IsFloating)
            //     dockingManager.MainDocumentPane =
            //         (DocumentPane) dockingManager.ActiveDocument.ContainerPane;
            Documents.Add(child);
            child.Activate();
        }

        private void Open(object sender, ExecutedRoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog {Multiselect = true};
            if (openFileDialog.ShowDialog() != true) return;
            foreach (var fileName in openFileDialog.FileNames)
            {
                Documents.Add(new ChildWindow(fileName));
            }
            dockingManager.ActiveContent = Documents.Last();
        }

        private void WindowTextInput(object sender, TextCompositionEventArgs e)
        {
            if (!menu.IsKeyboardFocusWithin &&
                _lastActiveChild != null &&
                _lastActiveChild.IsFloating)
                _lastActiveChild._textEditor.TextArea.RaiseEvent(e);
        }

        public void OpenFiles(IEnumerable<string> fileNames)
        {
            foreach (var fileName in fileNames)
            {
                Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                       (ParameterizedThreadStart) OpenFile, fileName);
            }
        }

        public void OpenFile(object fileName)
        {
            lock (Documents)
            {
                Documents.Add(new ChildWindow((string) fileName));
                dockingManager.ActiveDocument = Documents.Last();
                Activate();
            }
        }

        private void WindowDragOver(object sender, DragEventArgs e)
        {
            var fileNames = e.Data.GetData(DataFormats.FileDrop) as string[];
            if (fileNames == null || fileNames.Length == 0)
                e.Effects = DragDropEffects.None;
        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            new NotifyIconManager(this, "TrayMenu");
            OpenFiles(AppInstanceManager.SturtupArgs);
            AppInstanceManager.RunArgumentReciver();
        }

        private void DockingManagerDrop(object sender, DragEventArgs e)
        {
            var fileNames = e.Data.GetData(DataFormats.FileDrop) as string[];
            if (fileNames != null) OpenFiles(fileNames);

            var text = e.Data.GetData(DataFormats.Text) as string;

            if (text != null)
            {
                var newDocuments = Documents.Where(d => _newDocNameRegex.IsMatch(d.Title));

                var nameForNewDocument = "New " + ++_countOfNewDocuments;
                do
                {
                    var documentName = nameForNewDocument;
                    var documentWithSameName = newDocuments.
                        FirstOrDefault(d => d.Title == documentName);
                    if (documentWithSameName == null) break;
                    nameForNewDocument = "New " + ++_countOfNewDocuments;
                } while (true);

                var child = ChildWindow.CreateNew(nameForNewDocument);
                child._textEditor.Text = text;
                Documents.Add(child);
            }

            /*
text = e.Data.GetData(DataFormats.Html) as string;

if (text != null)
{
    var count = Documents.
    Where(d => _newDocNameRegex.IsMatch(d.Title)).Count() + 1;
    Documents.Add(ChildWindow.CreateNew("New (" + count + ")"));
    (Documents.Last() as ChildWindow)._textEditor.Text = text;
}
             */
        }

        private void SearchExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            _searchAndReplaceDialog.Find();
        }

        private void ReplaceExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            _searchAndReplaceDialog.tabControl1.SelectedItem =
                _searchAndReplaceDialog.tabItem2;

            if (_searchAndReplaceDialog.ReplacePatternTextBox.Text == string.Empty ||
                !_searchAndReplaceDialog.IsVisible)
            {
                _searchAndReplaceDialog.Show(dockingManager, AnchorStyle.Right);
                //_searchAndReplaceDialog.Activate();
                //_searchAndReplaceDialog.ToReplaceTextBox.Focus();
            }
            else
            {
                _searchAndReplaceDialog.Find();
            }
        }

        private void FindExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            _searchAndReplaceDialog.tabControl1.SelectedItem =
                _searchAndReplaceDialog.tabItem1;

            if (_searchAndReplaceDialog.SearchPatternTextBox.Text == string.Empty ||
                !_searchAndReplaceDialog.IsVisible)
            {
                _searchAndReplaceDialog.Show(dockingManager, AnchorStyle.Right);
                //_searchAndReplaceDialog.Activate();
                //_searchAndReplaceDialog.ToSearchTextBox.Focus();
            }
            else
            {
                _searchAndReplaceDialog.Find();
            }
        }

        private void SetDefaultTheme(object sender, RoutedEventArgs e)
        {
            ThemeFactory.ResetTheme();
        }

        private void ChangeCustomTheme(object sender, RoutedEventArgs e)
        {
            var uri = (string) ((MenuItem) sender).Tag;
            ThemeFactory.ChangeTheme(new Uri(uri, UriKind.RelativeOrAbsolute));
        }

        private void ChangeStandardTheme(object sender, RoutedEventArgs e)
        {
            var name = (string) ((MenuItem) sender).Tag;
            ThemeFactory.ChangeTheme(name);
        }

        private void ChangeColor(object sender, RoutedEventArgs e)
        {
            ThemeFactory.ChangeColors((Color) ColorConverter.ConvertFromString(((MenuItem) sender).Header.ToString()));
        }

        private void DocumentPaneMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (!(e.OriginalSource is Border)) return;
            dockingManager.MainDocumentPane = (DocumentPane) sender;
            if (e.ChangedButton == MouseButton.Left) New(null, null);
            if (e.ChangedButton == MouseButton.Right) Open(null, null);
        }

        private void DockingManagerPreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var documentPanes = dockingManager.LogicalDescendants<DocumentPane>();

            foreach (var pane in documentPanes)
            {
                pane.MouseDoubleClick -= DocumentPaneMouseDoubleClick;
                pane.MouseDoubleClick += DocumentPaneMouseDoubleClick;
            }

            if (dockingManager.Documents.Count != 0 || !(e.OriginalSource is Border)) return;
            if (e.ChangedButton == MouseButton.Left) New(null, null);
            if (e.ChangedButton == MouseButton.Right) Open(null, null);
        }

        private void DockingManagerPreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            //var t = 0;
            /*
            if (dockingManager.Documents.Count != 0 || !(e.OriginalSource is Border)) return;
            if (e.ChangedButton == MouseButton.Left) New(null, null);
            if (e.ChangedButton == MouseButton.Right) Open(null, null);
             * */
        }

        private void DockingManagerActiveDocumentChanged(object sender, EventArgs e)
        {
            if (dockingManager.ActiveDocument != null)
            {
                if (dockingManager.ActiveContent == null)
                    dockingManager.ActiveDocument.Activate();
                else
                {
                    var fakeActiveDocument = dockingManager.ActiveContent as DocumentContent;
                    if (fakeActiveDocument != null && fakeActiveDocument != dockingManager.ActiveDocument)
                        dockingManager.ActiveDocument.Activate();
                }
                return;
            }

            LineNumberStatusBarItem.Content = string.Empty;
            FilePathStatusBarItem.Content = string.Empty;
            FilePathStatusBarItem.ToolTip =
                "Use 'Left mouse button' single click or 'Space' key for creating new document." + Environment.NewLine +
                "Use 'Right mouse button' single click or 'Enter' key for open document.";
        }

        private void OnShowDocumentContent(object sender, RoutedEventArgs e)
        {
            var selectedDocument = ((MenuItem) e.OriginalSource).DataContext as DocumentContent;
            if (selectedDocument != null) selectedDocument.Activate();
        }

        private void OnShowDockableContent(object sender, RoutedEventArgs e)
        {
            var selectedContent = ((MenuItem) e.OriginalSource).DataContext as DockableContent;

            if (selectedContent == null) return;
            if (selectedContent.State != DockableContentState.Docked)
            {
                selectedContent.Show(dockingManager, AnchorStyle.Right);
            }

            selectedContent.Activate();
        }
    }
}
